<?xml version="1.0" encoding="UTF-8"?>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta http-equiv="Content-Language" content="fr" />
        <meta name="Author" content="Laboratoire Sun - SUPINFO Paris" />
        <meta name="owner" content="labo-sun@supinfo.com" />
        <meta name="Identifier-URL" content="http://www.labo-sun.com/" />
        <meta name="Reply-to" content="labo-sun@supinfo.com" />
        <meta name="revisit-after" content="10 days" />
        <meta name="Robots" content="index, follow" />
        <meta name="Description" content="Cet article a pour but d'initier le lecteur à la programmation 3D avec le langage Java. Nous allons créer un objet, en l'occurrence une pyramide, qui occupe un volume, et apprendre à le faire bouger." />
        <meta name="Publisher" content="Laboratoire Sun - SUPINFO Paris" />
        <meta name="Copyright" content="© 2000-2006 Laboratoire Sun - SUPINFO Paris" />
        <link type="text/css" rel="stylesheet" href="./css/template.css" />
        <link type="text/css" rel="stylesheet" href="./css/SyntaxHighlighter.css" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Découvrir la
			programmation 3D en Java - Articles - 1/1 -
			Java &amp; Solaris par le Laboratoire SUPINFO des technologies Sun </title>
        <script language="javascript" src="./js/shInit.js" />
        <script language="javascript" src="./js/shCore.js" />
        <script language="javascript" src="./js/shBrushCpp.js" />
        <script language="javascript" src="./js/shBrushCSharp.js" />
        <script language="javascript" src="./js/shBrushCss.js" />
        <script language="javascript" src="./js/shBrushDelphi.js" />
        <script language="javascript" src="./js/shBrushJava.js" />
        <script language="javascript" src="./js/shBrushJScript.js" />
        <script language="javascript" src="./js/shBrushPhp.js" />
        <script language="javascript" src="./js/shBrushPython.js" />
        <script language="javascript" src="./js/shBrushRuby.js" />
        <script language="javascript" src="./js/shBrushSql.js" />
        <script language="javascript" src="./js/shBrushVb.js" />
        <script language="javascript" src="./js/shBrushXml.js" />
        <keywords>java3D,howto,polygone,cube,Java,GUI,Java SE,decouvrir,la,programmation,3d,en,java,articles,1,1,certification,sun,java,solaris,articles,essentiels,tips,astuces,codes,exemple,tutorial,developpement,jsp,servlet,jdbc,jdo,j2se,j2ee,laboratoire</keywords>
        <author>Imad NABLI</author>
    </head>
    <body>
        <div class="chapter">
            <h2>Introduction</h2>
            <div class="subChapter">
                <p>Cet article a pour but d'initier le lecteur à la programmation 3D avec le langage Java.
					Nous allons créer un objet, en l'occurrence une pyramide, qui occupe un volume, et apprendre,
					soit à la faire bouger en réponse à une action de l'utilisateur, soit à l'animer en toute
					indépendance selon un temps et une loi bien définis. En réalité, faire de la « vraie » 3D
					reviendrait à programmer quelque chose de bien plus complexe que cela. En effet, une scène
					ne devient réellement impressionnante et esthétique que quand on gère l'éclairage et que les faces
					des objets que l'on crée sont dotées de textures. Dans cet article, nous ne verrons pas ces deux
					derniers points mais nous nous concentrerons sur la base de la programmation 3D d'un objet « simple ».</p>
                <p>
                    <a href="http://java.sun.com/products/java-media/3D/downloads/index.html" target="_blank">&gt; Télécharger l'API Java 3D</a>
                </p>
            </div>
        </div>
        <div class="chapter">
            <div class="subChapter">
                <h3>1. La création de volumes</h3>
                <p>Pour créer notre pyramide, il suffit de définir les triangles qui l'enveloppent
					et de les assembler. Une fois cette réalisation faite, il sera relativement facile
					de travailler avec les polygones plus complexes.</p>
                <p>L’objectif de ce chapitre est de créer une pyramide régulière à 4 faces triangulaires,
					dont la base est un carré. Chacune des faces sera de couleur différente pour mieux les
					différencier, et nous considérerons la base de la pyramide comme un carré divisé
					en 2 triangles, le long de la diagonale de celui-ci.
					Par conséquent, la pyramide sera finalement composée de 6 triangles.</p>
                <textarea name="code" class="java" rows="10" cols="59">private void makePyramide() {
					TriangleArray pyramide = new TriangleArray(18, TriangleArray.COORDINATES | TriangleArray.COLOR_3);
					float sommets[] = new float[vertices.length];
					for (int i = 0; i
					&lt; sommets.length; i++)
					sommets[i] = vertices[i] * echelle;
					pyramide.setCoordinates(0, sommets);
					pyramide.setColors(0, couleurs);
					setGeometry(pyramide);
					}</textarea>
                <p>Pour créer un triangle, nous devons dériver la classe abstraite Shape3D
					et dans notre classe, nous devons définir un tableau de 3 points:
					un pour chaque sommet du triangle. Ainsi pour créer notre pyramide, nous
					devons logiquement déclarer un tableau de 18 points qui, par groupes de 3,
					décrivent les sommets de nos 6 triangles. Ensuite nous faisons subir 2 rotations
					à notre pyramide dans le but de pouvoir apprécier notre travail avec de la perspective.</p>
                <p style="TEXT-ALIGN: center" align="center">
                    <img src="images/fig1.jpg" />
                </p>
                <p>
                    <i style="mso-bidi-font-style: normal">
                        <span style="font-size:8pt">
                            Figure 1 : La pyramide en 3D, Java a appliqué un algorithme de culling
							(
                            <a href="java/MaPyramide.java" target="_blank">
                                &gt;
                                <em>Sources complètes
									de la figure 1</em>
                            </a>
                            )
                        </span>
                    </i>
                </p>
                <textarea name="code" class="java" rows="5" cols="59">Transform3D rotate1 = new Transform3D();
					rotate1.rotX(-Math.PI / 9.0f);
					Transform3D rotate2 = new Transform3D();
					rotate2.rotY(Math.PI / 6.0f);
					rotate1.mul(rotate2);</textarea>
                <p>La figure 1 nous montre que Java3D a automatiquement appliqué un algorithme de culling
					à notre objet: nous allons découvrir en quoi consiste ce procédé dans le prochain chapitre.</p>
            </div>
            <div class="subChapter">
                <h3>2. Le Culling: un algorithme 3D</h3>
                <p>Si l'on regarde bien la figure 1 (voir ci-dessus), un des triangles définissant
					la base de notre pyramide (ici de couleure blanche) n'apparaît pas:
					il n'est pas déssiné par Java. Le premier réflexe serait de penser que nous avons
					fait une erreur dans la détermination de nos coordonnées. En réalité, nos coordonnées
					sont exactes mais nous ne les avons pas données dans le bon ordre. Nous venons de mettre
					en évidence un aspect du package Java3D: le culling. Appliqué par défaut aux objets créés,
					le culling consiste à ne pas afficher les parties de la scène qui ne seraient pas visibles,
					(ex: le dos d'une personne vue de face). Le culling a besoin que les faces soient « orientées »
					pour être appliquer correctement. Par conséquent,les coordonnées doivent toujours
					respecter le sens trigonométrique que l'on connait en mathématiques.</p>
                <center>
                    <p>
                        <img src="images/fig2trigo.jpg" />
                    </p>
                </center>
                <!-- si possible, refaire la figure -->
                <p>
                    <i style="mso-bidi-font-style: normal">
                        <span style="FONT-SIZE: 8pt">
                            Sens trigonométrique : Respecter toujours ce sens pour ne pas avoir
							de mauvaises surprises
                            <o:p xmlns:o="o" />
                        </span>
                    </i>
                </p>
                <p>Ainsi il faut respecter cette convention si l'on veut obtenir un fond plein
					pour notre pyramide. Pour cela, il faut regarder la face blanche dans un repère
					orthonormé (la face blanche pour simplifier le repère), avec un des axes dans notre
					direction, c'est-à-dire avec la pointe de la flèche pointant vers notre oeil.
					Ensuite, il faut énumérer les points des sommets dans le sens trigonométrique,
					c'est-à-dire dans le sens contraire des aiguilles d'une montre (figure 2).
					Voici donc le résultat une fois cette opération effectuée:</p>
                <p style="TEXT-ALIGN: center" align="center">
                    <img src="images/fig2.jpg" />
                </p>
                <p>
                    <i style="mso-bidi-font-style: normal">
                        <span style="FONT-SIZE: 8pt">
                            Figure 2 : La pyramide en 3D, avec le fond blanc.
							( Regarder les sources et enlever les commentaires pour obtenir ce résultat)
                            <o:p xmlns:o="o" />
                        </span>
                    </i>
                </p>
            </div>
        </div>
        <div class="chapter">
            <div class="subChapter">
                <h3>3. Les intéractions avec l'objet 3D</h3>
                <p>Nous allons essayer de donner vie à notre objet. Nous commencerons par les
					intéractions pour ensuite aborder brièvement l'animation de l'objet. Le but
					étant bien entendu de mixer les deux modes. Un exemple intéressant vient avec
					la distribution de Java3D: Gearbox. l'animation met en scène des engrenages
					tournant en continu avec lesqules nous pouvons interagir avec la souris pour
					changer l'orientation et le point de vue.</p>
                <p>
                    <img src="images/fig3.jpg" />
                </p>
                <p style="TEXT-ALIGN: center" align="center">
                    <i style="mso-bidi-font-style: normal">
                        <span style="FONT-SIZE: 8pt">Figure 3 : GearBox, la puissance de Java3D</span>
                    </i>
                </p>
                <p>Pour interagir avec notre objet, il faut définir un comportement lorsque
					l'utilisateur, par exemple, appuiera sur une touche de son clavier ou de sa souris.
					Pour cela, il faut dériver la classe Behavior (comportement en anglais) et le
					contenu de notre classe doit respecter ces 3 règles incontournables:</p>
                <p style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt">
                    <span style="mso-list: Ignore">
                        1)
                        <span style="FONT: 7pt 'Times New Roman'">     </span>
                    </span>
                    Dans le constructeur de la classe,
					il faut stocker une référence sur le groupe de transformations concerné.
                </p>
                <p style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt">
                    <span style="mso-list: Ignore">
                        2)
                        <spa style="FONT: 7pt 'Times New Roman'">     </spa>
                    </span>
                    Il faut redéfinir la méthode initialize().
					C’est ici qu’il faut déclarer à quels événements nous devons réagir.
                </p>
                <p style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt">
                    <span style="mso-list: Ignore">
                        3)
                        <span style="FONT: 7pt 'Times New Roman'">     </span>
                    </span>
                    Il faut redéfinir la méthode processStimulus()
					qui est automatiquement invoquée par Java3D. En effet c’est dans cette méthode qu’il
					faut retrouver l’origine de l’appel en y répondre en modifiant à la volée la
					transformation du groupe de transformations.
                </p>
                <p style="MARGIN-LEFT: 18pt">
                    Voici un extrait du code de
                    <a href="java/MaPyramideInteraction.java" target="_blank">&gt;
						MaPyramideInteraction.java</a>
                     :
                </p>
                <p>
                    <textarea name="code" class="java" rows="20" cols="59">public class PyramideBehavior extends Behavior {
						private TransformGroup targetTG;
						private Transform3D rotation = new Transform3D();
						private float angle = 0.0f;
						PyramideBehavior(TransformGroup targetTG) {
						this.targetTG = targetTG;
						}
						public void initialize() {
						this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
						}
						public void processStimulus(Enumeration criteria) {
						angle += 0.1f;
						rotation.rotX(angle);
						targetTG.setTransform(rotation);
						this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
						}
						}</textarea>
                </p>
                <p>Nous devons ensuite rendre active notre casse en modifiant légèrement le code
					d'initialisation de la branche d'animation (figure 4).</p>
                <p style="TEXT-ALIGN: center" align="center">
                    <img src="images/fig4.jpg" />
                </p>
                <p>
                    <textarea name="code" class="java">TransformGroup tg = new TransformGroup();
						tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
						branche.addChild(tg);
						tg.addChild(new Pyramide(2.0));
						PyramideBehavior behavior = new PyramideBehavior(tg);
						behavior.setSchedulingBounds(new BoundingSphere());
						branche.addChild(behavior);</textarea>
                </p>
                <p>Comme le montre la figure 4, notre classe Behavior est intégrée à la branche.
					Deux spécificités sont à retenir dans le code:</p>
                <p style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt">
                    <span style="mso-list: Ignore">
                        1)
                        <span style="FONT: 7pt 'Times New Roman'">     </span>
                    </span>
                    Nous devons rendre notre groupe de
					transformations capable d'être modifié à la volée, ce que nous faisons en appelant
					la méthode setCapability
                </p>
                <p style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt">
                    <span style="mso-list: Ignore">
                        2)
                        <span style="FONT: 7pt 'Times New Roman'">     </span>
                    </span>
                    Il faut voir que setSchedulingBounds reçoit
					un objet BoundingSphere et qui se charge de définir la zone de l'espace qui sera
					affectée par la transformation.
                </p>
                <p>Dans notre code, on utilisea sphère englobante (d'où le nom BoundingSphere). D'autres
					solutions sont possibles, telles que le polygone englobant. Par défaut, la sphère est
					centrée sur le repère et a un rayon de 1. Par conséquent, toute la scène est modifié dans
					notre exemple car tout tient désormais dans cette sphère. Dans ce premier exemple,
					nous réagissons à l'appui de n'importe quelle touche du clavier pour faire tourner
					notre pyramide autour de l'axe des abscisses (l'axe x). Nous aborderons dans le chapitre
					suivant comment faire le détail précis des événements, car Java3D propose des classes
					de haut niveau très intéressantes comme nous pouvons le voir dans ce tableau non exhaustif:</p>
                <p align="center" />
                <table class="MsoTableGrid" id="Table1" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-yfti-tbllook: 480; mso-border-insideh: .5pt solid windowtext; mso-border-insidev: .5pt solid windowtext" cellspacing="0" cellpadding="0" border="1">
                    <tbody>
                        <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes">
                            <td valign="top">
                                <p class="MsoNormal" style="TEXT-ALIGN: center" align="center">
                                    <b style="mso-bidi-font-weight: normal">
                                        Critères de Réveil
                                        <o:p xmlns:o="o" />
                                    </b>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="TEXT-ALIGN: center" align="center">
                                    <b style="mso-bidi-font-weight: normal">
                                        Description
                                        <o:p xmlns:o="o" />
                                    </b>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 1">
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">WakeupOnActivation</span>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand la plate-forme de vue intersecte avec la
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">région
										englobante.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 2">
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">WakeupOnAWTEvent</span>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand un ou plusieurs événements AWT
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">spécifiques se
										produisent.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 3">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnBehaviorPost
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand un objet Behavior spécifique poste un
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">événement
										spécifique.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 4">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnCollisionEntry
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche à la
										première détection d'une collision entre un
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">objet spécifique
										et tout autre objet de la scène.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 5">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnCollisionExit
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">Se déclenche
										quand l'objet spécifique n'est plus en collision.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 6">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnCollisionMovement
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand l'objet se déplace, tout en étant en
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">collision.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 7">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnDeactivation
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand la plate-forme de vue n'intersecte plus
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">avec la région
										englobante.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 8">
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        WakeupOnElapsedFrames
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <o:p xmlns:o="o"> </o:p>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal" style="mso-layout-grid-align: none">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">
                                        Se déclenche
										quand un nombre de frames spécifiques ont
                                        <o:p xmlns:o="o" />
                                    </span>
                                </p>
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">été
										rendus.</span>
                                </p>
                            </td>
                        </tr>
                        <tr style="mso-yfti-irow: 9; mso-yfti-lastrow: yes">
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">WakeupOnElapsedTime</span>
                                </p>
                            </td>
                            <td valign="top">
                                <p class="MsoNormal">
                                    <span style="FONT-SIZE: 8pt; COLOR: black; FONT-FAMILY: Arial">Se déclenche
										après un nombre de millisecondes spécifiques</span>
                                </p>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <p class="MsoNormal" style="mso-layout-grid-align: none">
                    <b>
                        <span style="FONT-SIZE: 9pt; COLOR: white; FONT-FAMILY: Arial">
                            Critères de Réveil
							Description
                            <o:p xmlns:o="o" />
                        </span>
                    </b>
                </p>
            </div>
        </div>
        <div class="chapter">
            <div class="subChapter">
                <h3>Conclusion</h3>
                <p>La programmation en Java3D est accessible à toute personne désirant
					aller plus loin dans son apprentissage du langage Java. Les librairies
					java sont complètes et beaucoup de tutoriaux sont disponibles sur le web.
					Cette première initiation doit amener le lecteur à découvrir d'autres
					algorithmes 3D, et la création d'objets est infinie. Vient ensuite tout le
					travail de texture et d'éclairage qui permet de rendre encore plus
					esthétique le rendu.</p>
                <p>Pour aller plus loin:</p>
                <p class="MsoNormal">
                    <span style="mso-tab-count: 1">           </span>
                    <a href="http://www.eteks.com/coursjava/java3D.html" target="_blank">&gt;http://www.eteks.com/coursjava/java3D.html</a>
                </p>
                <p class="MsoNormal">
                    <span style="mso-tab-count: 1">           </span>
                    <a href="http://raphaello.univ-fcomte.fr/IG/Java3D/Java3D.htm" target="_blank">&gt;http://raphaello.univ-fcomte.fr/IG/Java3D/Java3D.htm</a>
                </p>
                <p>
                    <i style="mso-bidi-font-style: normal">
                        <span style="FONT-SIZE: 8pt">
                            Source et
							bibliographie : Ce tutorial est inspiré d’un article paru dans le
							mensuel
                            <u>Programmez</u>
                            de février 2004
                        </span>
                    </i>
                </p>
            </div>
        </div>
        <div class="chapter">
            <div class="subChapter">
                <h3>5. Les animations</h3>
                <p>
                    Une animation se définit par un comportement particulier: un objet
					bouge tout seul. Par conséquent, les classes gérant les animations,
					appelées « Interpolators », dérivent toutes de la classe
					abstraite Behavior. Comme leur nom l'indique, les interpolateurs réalisent
					des interpolations linéaires entre 2 extrêmes, selon un rythme et dans
					un sens défini par un objet Alpha. Le terme Alpha, à ne pas confondre avec
					celui utilisé pour le mélange de couleurs alpha d'autres librairies 3D,
					s'explique par le fait que cetteclasse gère la croissance et la décroissance
					d'une valeur entre 0 et 1, rappelant le comportement d'une sinusoïde. La
					classe Alpha a de nombreuses potentialités, c'est une sorte de métronome
					pour l'animation, celle-ci se répétant autant de fois que l'on souhaite ou
					bien indéfiniment. Pour notre exemple, on fait tourner indéfiniment notre
					pyramide autour de l'axe vertical, Alpha prend 60 secondes pour passer de
					0 à 1. Ainsi nous définissons implicitement une vitesse de rotation de 1 tour
					par minute. Voic le code extrait de
                    <a href="java/MaPyramideAnimation.java" target="_blank">&gt;MaPyramideAnimation.java </a>
                    :
                </p>
                <p>
                    <textarea name="code" class="java" rows="20" cols="59">BranchGroup branche = new BranchGroup();
						TransformGroup tg = new TransformGroup();
						tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
						branche.addChild(tg);
						tg.addChild(new Pyramide(2.0));
						//Alpha alpha = new Alpha(-1, 60000);
						Alpha alpha = new Alpha(3, 4000);
						RotationInterpolator ri = new RotationInterpolator(alpha, tg);
						/* //Les lignes suivantes pour une rotation de Pi/4 autour de l’axe
						Transform3D rot = new Transform3D();
						rot.rotX((float)Math.PI/- 4.0f);
						RotationInterpolator ri = new RotationInterpolator(alpha, tg, rot, 0.0f, (float)(2.0*Math.PI));
						*/
						ri.setSchedulingBounds(new BoundingSphere());
						branche.addChild(ri);</textarea>
                </p>
                <p align="center">
                    <img src="images/fig6.jpg" />
                </p>
                <p>Avant de tourner autour de l'axe vertical faisant tourner celui-ci
					de Pi/4 autour de l'axe horizontal. La scène prend donc plus de relief.
					Pour cela, il faut remplacer la ligne où l'on construit l'interpolateur
					par les 3 lges en commentaires dans le code précédent.</p>
                <p>
                    De même qu'il y a des classes « Behavior » de haut niveau,
					il y a des classes d'interpolation de haut niveau qui permettent d'enchaîner
					les animations. Le programme
                    <a href="java/MaPyramideAnimationAxe.java" target="_blank">&gt;MaPyramideAnimationAxe.java</a>
                    en montre un exemple.
                </p>
                <p class="MsoNormal" style="TEXT-ALIGN: center" align="center">
                    <v:shape xmlns:v="v" id="_x0000_i1026" style="WIDTH: 244.5pt; HEIGHT: 244.5pt" type="#_x0000_t75" />
                </p>
                <p align="center">
                    <img src="images/fig7.jpg" />
                </p>
            </div>
        </div>
        <div class="chapter">
            <div class="subChapter">
                <h3>4. La gestion des événements</h3>
                <p>Les pré-requis pour la gestion des événements d'une scène demande de bien
					connaître la documentation Java relative aux événements AWT et de savoir se
					débrouiller avec les énumérations. En effet, la méthode processStimulus peut
					être invoquée à la demande d'un ou de plusieurs critères, parfois en simultanée.
					Et c'est dans une énumération que les critères sont transmis en paramètre à la méthode.
					Donc pour retrouver à quel critère on a à faire, il faut pouvoir parcourir
					aisément l'énumération. Dans le cas d'un critère AWT, il faut ensuite connaître
					quel(s) événement(s), simultanés ou pas, est (sont) à l'origine de l'appel de la
					méthode. C'est pour cette raison que l'objet critère range ces événements
					dans un tableau que nous devons donc aussi parcourir. Ensuite, il suffit
					d'interroger chaque événement pour savoir ce qui se passe véritablement.</p>
                <p>
                    Voici un extrait du code
                    <a href="java/MaPyramideInteractionTouchesSouris.java" target="_blank">&gt;MaPyramideInteractionTouchesSouris.java</a>
                    ,
					dans cet extrait on filtre l'appui sur les touches x, y, z pour effectuer
					une rotation respectivement autour des axes de mêmes noms, et un clique sur
					la souris remet la pyramide à sa position initiale:
                </p>
                <p>
                    <textarea name="code" class="java" rows="40" cols="59">public void processStimulus(Enumeration criteria) {
						WakeupCriterion wakeup;
						AWTEvent[] events;
						AWTEvent event;
						int id;
						while (criteria.hasMoreElements()) {
						wakeup = (WakeupCriterion) criteria.nextElement();
						if (wakeup instanceof WakeupOnAWTEvent) {
						events = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
						for (int i = 0; i
						&lt; events.length; i++) {
						event = events[i];
						id = event.getID();
						if (id == KeyEvent.KEY_PRESSED) {
						switch (((KeyEvent) event).getKeyCode()) {
						case KeyEvent.VK_X :
						anglex += 0.1f;
						rotationx.rotX(anglex);
						break;
						case KeyEvent.VK_Y :
						angley += 0.1f;
						rotationy.rotY(angley);
						break;
						case KeyEvent.VK_Z :
						rotationz.rotZ(anglez);
						anglez += 0.1f;
						break;
						default :
						break;
						}
						// reset de la matrice
						rotation.setIdentity();
						rotation.mul(rotationx);
						rotation.mul(rotationy);
						rotation.mul(rotationz);
						}
						if (id == MouseEvent.MOUSE_PRESSED) {
						if (((MouseEvent) event).getButton() == MouseEvent.BUTTON1) {
						anglex = 0.0f;
						angley = 0.0f;
						anglez = 0.0f;
						rotationx.rotX(anglex);
						rotationx.rotY(angley);
						rotationx.rotZ(anglez);
						rotation.setIdentity();
						}
						}
						}
						}
						}
						targetTG.setTransform(rotation);
						this.wakeupOn(new WakeupOnAWTEvent(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK));
						}</textarea>
                </p>
                <p style="TEXT-ALIGN: center" align="center">
                    <i style="mso-bidi-font-style: normal">
                        <span style="FONT-SIZE: 8pt">Figure 5 :
							Rotation autour des axes</span>
                    </i>
                </p>
            </div>
        </div>
    </body>
</html>

